package fabrik;

import java.util.ArrayList;
import java.util.Collections;


/**
 * This class represents the process, which contain a list of predeccessors and
 * successors.
 * @author Janet
 *@version 1.0
 */
public class Process {
	// ArrayList of predeccessors of the process
	private ArrayList<Relations> pre;
	// ArrayList of successor of the process
	private ArrayList<Relations> successor;
	// name of the process
	private String name;
	// the int values
	private int iD;
	private int period;
	// projects
	private Project project;
	// int values
	private Integer fEZ;
	private Integer fAZ;
	private Integer sEZ;
	private Integer sAZ;
	private Integer totalPuffer;
	private Integer freePuffer;

	/**
	 * The constructor of the class process.
	 * 
	 * @param name
	 *            saves the name of the process
	 * @param iD
	 *            shows the iD of the process
	 * @param period
	 *            the time how long it takes
	 * @param project
	 *            , the project
	 */
	public Process(String name, int iD, int period, Project project) {
		this.period = period;
		this.iD = iD;
		this.name = name;
		pre = new ArrayList<Relations>();
		successor = new ArrayList<Relations>();
		this.project = project;
	}

	/**
	 * gets the list of relations of the pre.
	 * 
	 * @return the element pre
	 */
	public ArrayList<Relations> getPreRelListe() {
		return pre;
	}

	/**
	 * Sets the pre element.
	 * 
	 * @param pre
	 *            ,the predecessor of the process
	 */
	public void setPre(ArrayList<Relations> pre) {
		this.pre = pre;
	}

	/**
	 * the successor relation list.
	 * 
	 * @return the successor element
	 */
	public ArrayList<Relations> getSuccessorRelListe() {
		return successor;
	}

	/**
	 * sets the successor of the process.
	 * 
	 * @param successor
	 *            , succesor in the list
	 */
	public void setSuccessor(ArrayList<Relations> successor) {
		this.successor = successor;
	}

	/**
	 * getter for name.
	 * 
	 * @return name of the process
	 */
	public String getName() {
		return name;
	}

	/**
	 * setter for name.
	 * 
	 * @param name
	 *            of the process
	 */

	public void setName(String name) {
		this.name = name;
	}

	/**
	 * getter for ID.
	 * 
	 * @return iD of the process
	 */
	public int getID() {
		return iD;
	}

	/**
	 * setter for iD.
	 * 
	 * @param id
	 *            of the process
	 */
	public void setID(int id) {
		iD = id;
	}

	/**
	 * getter for period.
	 * 
	 * @return period
	 *            , of the process
	 */
	public int getPeriod() {
		return period;
	}

	/**
	 * setter for period.
	 * 
	 * @param period
	 *            of the process
	 */
	public void setPeriod(int period) {
		this.period = period;
	}

	/**
	 * If the fez value is not set, do the forward calculation.
	 * 
	 * @return fEZ value
	 */
	public int getFEZ() {
		if (fEZ == null)
			calculateForward();
		return fEZ;
	}

	/**
	 * setter for fez.
	 * 
	 * @param fEZ
	 *            of the process
	 */
	public void setFEZ(int fEZ) {
		this.fEZ = fEZ;
	}

	/**
	 * If the faz value is not set, do the forward calculation.
	 * 
	 * @return fAZ value
	 */
	public int getFAZ() {
		if (fAZ == null)
			calculateForward();
		return fAZ;
	}

	/**
	 * setter for faz.
	 * 
	 * @param fAZ
	 *            of the process
	 */
	public void setFAZ(int fAZ) {
		this.fAZ = fAZ;
	}

	/**
	 * If the sez value is not set, do the backward calculation. else
	 * 
	 * @return sEZ value
	 */
	public int getSEZ() {
		if (sEZ == null)
			calculateBackward();
		return sEZ;
	}

	/**
	 * setter for sez.
	 * 
	 * @param sEZ
	 *            of the process
	 */
	public void setSEZ(int sEZ) {
		this.sEZ = sEZ;
	}

	/**
	 * If the saz value is not set, do the backward calculation.
	 * 
	 * @return sAZ value
	 */
	public int getSAZ() {
		if (sAZ == null)
			calculateBackward();
		return sAZ;
	}

	/**
	 * setter for saz .
	 * 
	 * @param sAZ
	 *            of the process
	 */
	public void setSAZ(int sAZ) {
		this.sAZ = sAZ;
	}

	/**
	 * This method returns the total puffer.
	 * 
	 * @return totalpuffer
	 */
	public int getTotalPuffer() {
		return totalPuffer;
	}

	/**
	 * setter for total puffer.
	 * 
	 * @param totalPuffer
	 *            of the process
	 */
	public void setTotalPuffer(int totalPuffer) {
		this.totalPuffer = totalPuffer;
	}

	/**
	 * This method gets the value of free puffer.
	 * 
	 * @return freePuffer, if not equal to null
	 */
	public int getFreePuffer() {
		if (freePuffer != null)
			return freePuffer;
		else
			return 0;
	}

	/**
	 * setter for free puffer.
	 * 
	 * @param freePuffer
	 *            ,of the process
	 */
	public void setFreePuffer(int freePuffer) {
		this.freePuffer = freePuffer;
	}

	/**
	 * The String to string method.
	 * @return the int values of a process
	 */
	@Override
	public String toString() {
		return "Process [ID=" + iD + ", name=" + name + ", pre=" + pre
				+ ", successor=" + successor + ", period=" + period + ",FAZ="
				+ fAZ + ",FEZ=" + fEZ + " ,SAZ=" + sAZ + ",SEZ=" + sEZ
				+ ",totalPuffer=" + totalPuffer + ",freePuffer=" + freePuffer
				+ " ]";
	}

	/**
	 * This is the method for the forward calculation.
	 */
	private void calculateForward() {
		ArrayList<Integer> fazs = new ArrayList<Integer>();
		ArrayList<Integer> fezs = new ArrayList<Integer>();
		// it goes through the predecessors list
		for (Relations rel : pre) {
			Process pre = rel.getPre();
			// it checks every element of the list of its relations and then
			// sets its
			// FAZ and FEZ values
			switch (rel.getType()) {
			case EA:
				fazs.add(pre.getFEZ());
				fezs.add(pre.getFEZ() + period);
				break;
			case AA:
				fazs.add(pre.getFAZ());
				fezs.add(pre.getFAZ() + period);
				break;
			case EE:
				fazs.add(pre.getFEZ() - period);
				fezs.add(pre.getFEZ());
				break;
			case AE:
				fazs.add(pre.getFAZ() - period);
				fezs.add(pre.getFAZ());
				break;
			default: System.out.println("Error!Invalid relation type.");
			}
		
		}
		// checks if the fazs list is empty, faz and fez are set the max values
		// in the list
		if (!fazs.isEmpty()) {
			fAZ = Collections.max(fazs);
			fEZ = Collections.max(fezs);
			// else faz is set to zero and fez the period.
		} else {
			fAZ = 0;
			fEZ = period;
		}
	}

	/**
	 * This method is the backward calculation, it works analog like the forward
	 * calculation, but in this case just backwards.
	 */
	private void calculateBackward() {
		ArrayList<Integer> sazs = new ArrayList<Integer>();
		ArrayList<Integer> sezs = new ArrayList<Integer>();
		// it goes through the successors list
		for (Relations rel : successor) {
			Process successor = rel.getSuccessor();
			// checks its cases and then sets the faz and fez when found
			switch (rel.getType()) {
			case EA:
				sazs.add(successor.getSAZ() - period);
				sezs.add(successor.getSAZ());
				break;
			case AA:
				sazs.add(successor.getSAZ());
				sezs.add(successor.getSAZ() + period);
				break;
			case EE:
				sazs.add(successor.getSEZ() - period);
				sezs.add(successor.getSEZ());
				break;
			case AE:
				sazs.add(successor.getSEZ());
				sezs.add(successor.getSEZ() + period);
				break;
			default: System.out.println("Error!Invalid relation type.");
			}
		}
		// checks if sazs list is empty, if so get the min values of the list
		if (!sazs.isEmpty()) {
			sAZ = Collections.min(sazs);
			sEZ = Collections.min(sezs);
			// else set saz to the project end minus its period
			// and the set to projectend
		} else {
			sAZ = project.getProjectEnd() - period;
			sEZ = project.getProjectEnd();
		}
	}
}
